package cn.turboinfo.fuyang.api.provider.admin.config;

import cn.turboinfo.fuyang.api.domain.common.service.user.SysUserService;
import cn.turboinfo.fuyang.api.domain.common.usecase.user.CommonListUserTypeUseCase;
import cn.turboinfo.fuyang.api.provider.admin.component.session.AdminSessionHelper;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.config.DefaultShiroFilterChainDefinitionCustomizer;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.credential.RetryLimitHashedCredentialsMatcher;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.filter.LoginOperationAuthenticationFilter;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.filter.RestAuthenticationFilter;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.helper.PasswordHelper;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.realm.SysUserRealm;
import cn.turboinfo.fuyang.api.provider.admin.framework.shiro.session.AdminSessionFactory;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;

import javax.servlet.Filter;
import java.util.Map;

@Configuration
public class AdminShiroConfig {

    @Bean
    protected static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    protected CredentialsMatcher credentialsMatcher(PasswordHelper passwordHelper) {
        return new RetryLimitHashedCredentialsMatcher(passwordHelper);
    }

    @Bean
    protected Realm realm(CredentialsMatcher credentialsMatcher) {
        SysUserRealm sysUserRealm = new SysUserRealm();
        sysUserRealm.setCredentialsMatcher(credentialsMatcher);
        return sysUserRealm;
    }

    @Bean
    protected AdminSessionFactory adminSessionFactory(SysUserService sysUserService, CommonListUserTypeUseCase commonListUserTypeUseCase) {
        return new AdminSessionFactory(sysUserService, commonListUserTypeUseCase);
    }

    @Bean
    protected AdminSessionHelper adminSessionHelper(AdminSessionFactory adminSessionFactory, FindByIndexNameSessionRepository<? extends Session> sessionRepository) {
        return new AdminSessionHelper(adminSessionFactory, sessionRepository);
    }

    @Bean
    protected ShiroFilterChainDefinition adminShiroFilterChainDefinition(DefaultShiroFilterChainDefinitionCustomizer customizer) {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        customizer.apply(chainDefinition);

        return chainDefinition;
    }

    @Bean
    protected ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager, ShiroFilterChainDefinition shiroFilterChainDefinition, AdminSessionHelper adminSessionHelper) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

        filterFactoryBean.setSecurityManager(securityManager);
        filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());

        Map<String, Filter> filters = filterFactoryBean.getFilters();

        filters.put("authc", new RestAuthenticationFilter());
        filters.put("authcAfter", new LoginOperationAuthenticationFilter(adminSessionHelper));

        filterFactoryBean.setFilters(filters);

        return filterFactoryBean;
    }

    @Bean
    protected CacheManager cacheManager() {
        return new MemoryConstrainedCacheManager();
    }
}
